package com.edu.lwh.service;

import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.PageUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.DistanceUnit;
import co.elastic.clients.elasticsearch._types.GeoLocation;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.core.search.HitsMetadata;
import co.elastic.clients.json.JsonData;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.edu.lwh.javabean.Hotel;
import com.edu.lwh.javabean.HotelDoc;
import com.edu.lwh.javabean.PageResult;
import com.edu.lwh.javabean.RequestParams;
import com.edu.lwh.mapper.HotelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.List;

@Service
public class HotelServiceImpl extends ServiceImpl<HotelMapper, Hotel> implements HotelService {
    @Autowired
    private ElasticsearchClient elasticsearchClient;

    private static final String INDEX_NAME = "hotel";

    @Override
    public PageResult search(RequestParams params) {

//        搜索。构造搜索对象。
//        Query.Builder queryBuilder = new Query.Builder();
//        if (ObjectUtil.isEmpty(params.getKey())) {
////            没有搜索关键词
//            queryBuilder.matchAll(builder -> builder);
//        } else {
//            queryBuilder.match(builder -> builder
//                    .field("all")
//                    .query(params.getKey()));
//        }
//        Query query = queryBuilder.build();

//        上面的用函数构造。
        Query query = this.buildBasicQuery(params);
        //模拟位置
        params.setLocation("31.03, 121.61");
//       分页。
        Integer size = params.getSize();
        int from = PageUtil.getStart(params.getPage() - 1, size);
        SearchResponse<HotelDoc> response;

//        搜索。
        try {
//            search 里面的Builder我们也抽取出来。
            SearchRequest.Builder searchBuilder = new SearchRequest.Builder();
            searchBuilder.index(INDEX_NAME)
                    .query(query)
                    .from(from)
                    .size(size)
                    .trackScores(true);
            String location = params.getLocation();
            if(ObjectUtil.isNotEmpty(location)){
                searchBuilder.sort(builder -> builder
                        .geoDistance(builder1 -> builder1
                                .field("location")
                                .location(GeoLocation.of(builder2 -> builder2
                                        .text(location)))
                                .order(SortOrder.Asc)
                                .unit(DistanceUnit.Kilometers)));
            }


            response = this.elasticsearchClient.search(
                    searchBuilder.build()
                    , HotelDoc.class);
            HitsMetadata<HotelDoc> hits = response.hits();
            List<HotelDoc> hotelDocList = CollStreamUtil.toList(hits.hits(), Hit::source);
            return new PageResult(hits.total().value(), hotelDocList);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }


    private Query buildBasicQuery(RequestParams params){
//        多个条件查询，我们用布尔查询。
        BoolQuery.Builder boolQueryBuilder = new BoolQuery.Builder();

//        关键字搜索。
        if(ObjectUtil.isEmpty(params.getKey())){
//            没有搜索关键词.
            boolQueryBuilder.must(builder -> builder.matchAll(builder1 -> builder1));
        }else{
            boolQueryBuilder.must(builder -> builder.match(builder1 -> builder1
                    .field("all").query(params.getKey())));
        }
//        城市条件.
        if(ObjectUtil.isNotEmpty(params.getCity())){
            boolQueryBuilder.filter(builder -> builder
                    .term(builder1 -> builder1
                            .field("city").value(params.getCity())));
        }
//        品牌条件
        if(ObjectUtil.isNotEmpty(params.getBrand())){
            boolQueryBuilder.filter(builder -> builder
                    .term(builder1 -> builder1
                            .field("brand").value(params.getBrand())));
        }
//        星级条件.
        if(ObjectUtil.isNotEmpty(params.getStarName())){
            boolQueryBuilder.filter(builder -> builder
                    .term(builder1 -> builder1
                            .field("starName").value(params.getStarName())));
        }
//        价格
        if(ObjectUtil.isAllNotEmpty(params.getMinPrice(),params.getMaxPrice())){
            boolQueryBuilder.filter(builder -> builder
                    .range(builder1 -> builder1
                            .field("price")
                            .gte(JsonData.of(params.getMinPrice()))
                            .lte(JsonData.of(params.getMaxPrice()))));
        }
//        构造Query对象。
        return new Query.Builder()
                .bool(boolQueryBuilder.build())
                .build();
    }
}
